1 /** 2 * Public imports free, malloc, realloc, memcpy, memcmp, memset. 3 * - toHeap!T executes malloc + memcpy 4 * - alloc!T is a malloc with the type size 5 * - allocSlice!T will return a heap allocated slice 6 * 7 */ 8 module hip.util.memory; 9 10 public import core.stdc.stdlib; 11 public import core.stdc.string:memcpy, memcmp, memset; 12 import hip.util.reflection; 13 14 version(WebAssembly) version = CustomRuntime; 15 version(PSVita) version = CustomRuntime; 16 version(CustomRuntimeTest) version = CustomRuntime; 17 @nogc: 18 void setZeroMemory(T)(ref T variable) 19 { 20 memset(&variable, 0, T.sizeof); 21 } 22 23 24 T* alloc(T)(size_t count = 1){return cast(T*)core.stdc.stdlib.malloc(T.sizeof*count);} 25 T[] allocSlice(T)(size_t count){return alloc!T(count)[0..count];} 26 27 void* toHeap(T)(in T data) if(isReference!T) 28 { 29 version(CustomRuntime) 30 { 31 void* m = cast(void*)data; //WASM don't need to allocate as it is not ever deleted. 32 } 33 else 34 { 35 import core.memory; 36 void* m = cast(void*)data; 37 GC.addRoot(cast(void*)data); 38 } 39 return m; 40 } 41 42 void* toHeap(T)(T data) if(!isReference!T) 43 { 44 void* m = alloc!T; 45 memcpy(m, &data, T.sizeof); 46 return m; 47 } 48 49 void[] toHeapSlice(T)(T data) if(!is(T == void[])) 50 { 51 return toHeap(data)[0..T.sizeof]; 52 } 53 54 55 void freeGCMemory(void* data, string f = __FILE__, size_t l = __LINE__) 56 { 57 assert(data !is null, "Tried to free null data."); 58 version(CustomRuntime) 59 { 60 static import rt.hooks; 61 rt.hooks.free(cast(ubyte*)data, f, l); 62 } 63 else 64 { 65 import core.memory; 66 GC.removeRoot(data); 67 GC.free(data); 68 } 69 } 70 71 void freeGCMemory(ref void* data, string f = __FILE__, size_t l = __LINE__) //Remove ref. 72 { 73 assert(data !is null, "Tried to free null data."); 74 version(CustomRuntime) 75 { 76 static import rt.hooks; 77 rt.hooks.free(cast(ubyte*)data, f, l); 78 } 79 else 80 { 81 import core.memory; 82 GC.removeRoot(data); 83 GC.free(data); 84 } 85 data = null; 86 } 87 88 void freeGCMemory(ref void[] data, string f = __FILE__, size_t l = __LINE__) 89 { 90 assert(data.length, "Tried to free null data."); 91 freeGCMemory(data.ptr, f, l); 92 data = null; 93 } 94 95 void freeGCMemory(T)(ref T[] data, string f = __FILE__, size_t l = __LINE__) 96 { 97 freeGCMemory(cast(void*)data.ptr, f, l); 98 data = null; 99 } 100 101 102 class Pool(T) if(is(T == class) || is(T == interface)) 103 { 104 private 105 { 106 T[] objects; 107 int deadCount, maxPoolSize = -1; 108 pragma(inline, true) T getFirstDead(){return objects[getActiveCount];} 109 110 struct TInterface 111 { 112 pragma(inline, true) 113 { 114 static void deinitialize(T obj){obj.deinitialize();} 115 static void initialize(T obj){obj.initialize();} 116 } 117 } 118 } 119 120 /** 121 * 122 * Params: 123 * maxPoolSize = -1 means that Pool will never return null. It may still give array out of bounds if too many objects are created. 124 */ 125 this(int maxPoolSize = -1) 126 { 127 this.maxPoolSize = maxPoolSize; 128 } 129 int getActiveCount() => cast(int)objects.length - deadCount; 130 131 T get(Args...)(Args a) 132 { 133 T ret; 134 if(deadCount > 0) 135 { 136 ret = getFirstDead(); 137 deadCount--; 138 } 139 else 140 { 141 if(objects.length + 1 > maxPoolSize) return null; 142 int activeCount = getActiveCount(); 143 objects.length++; 144 if(deadCount) 145 objects[$-1] = objects[activeCount]; 146 objects[activeCount] = ret = new T(a); 147 } 148 TInterface.initialize(ret); 149 return ret; 150 } 151 152 int opApply(scope int delegate(ref T) dg) 153 { 154 int result = 0; 155 156 foreach (i; 0..getActiveCount) 157 { 158 result = dg(objects[i]); 159 if (result) 160 break; 161 } 162 return result; 163 } 164 165 void kill(T instance) 166 { 167 TInterface.deinitialize(instance); 168 deadCount++; 169 } 170 void clear() 171 { 172 foreach(obj; this) TInterface.deinitialize(obj); 173 deadCount = cast(int)objects.length; 174 } 175 }